// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"internal/abi"
	"internal/goexperiment"
	"runtime/internal/atomic"
	"runtime/internal/sys"
	"unsafe"
)

// 我们有两种不同的延迟方式。旧的方法是在执行DEBER语句时创建一个
// DEBER记录，并将其添加到
// DEBER链中。此链由所有函数
// 出口处的deferreturn调用检查，以便运行适当的defer调用。一种更便宜的方法（我们称之为
// 开放编码延迟）用于在
// 循环中没有延迟语句的函数。在这种情况下，我们只需将defer函数/arg信息存储到每个defer语句点的特定堆栈槽中，并在位掩码中设置一个
// 位。在每个函数出口处，我们添加内联代码，根据堆栈上存储的位掩码和fn/arg信息，直接进行
// 适当的延迟调用。在panic/Goexit处理期间，适当的延迟调用是
// 使用额外的funcdata信息进行的，该信息指示
// 包含位掩码和延迟fn/args的确切堆栈插槽。

// 检查以确保我们真的能引起恐慌。如果死机
// 是从运行时生成的，或者是从malloc内部生成的，那么将
// 转换为一个消息抛出。
// pc应该是
// 触发此死机的编译器生成代码的程序计数器。
func panicCheck1(pc uintptr, msg string) {
	if sys.GoarchWasm == 0 && hasPrefix(funcname(findfunc(pc)), "runtime.") {
		// 注意：wasm无法跟踪呼叫，因此我们无法获取原始呼叫方的电脑。
		throw(msg)
	}
	// TODO:这是多余的吗？我们怎么可能在malloc 
	// 中，而不是在运行时中？可能是运行时/内部/*？
	gp := getg()
	if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
		throw(msg)
	}
}

// 同上，但允许从运行时调用。
// 
// 对于runtime.sigmanic生成的任何可能是
// 的死机，都必须使用此函数，因为这些死机总是由
// 运行时调用。
func panicCheck2(err string) {
	// 恐慌分配，因此为了避免递归malloc，将malloc期间的恐慌变成抛出。
	gp := getg()
	if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
		throw(err)
	}
}

// 以下许多紧急进入点在各种运行时上下文中发生时会变成抛出。这些情况在运行时绝对不应该发生在
// 中，如果发生，则表明存在严重问题，并且
// 不应该被用户代码捕获。
// 
// 由
// 编译器为越界索引表达式、
// 越界切片表达式、零除和负移位生成的代码调用panic{Index，Slice，divide，shift}函数。
// 当信号出现时，信号处理程序将调用（再次）panicdivide、panicoverflow、panicfloat和panicmem 
// 函数
// 指示各自的问题。
// 
// 因为从来没有直接调用过panic{Index，Slice，shift}，而
// 因为运行时包不应该有一个越界Slice 
// 或数组引用或负移位，如果我们看到从
// 运行时包调用的那些函数，我们就会把恐慌变成一次抛出。这将转储整个运行时堆栈，以便于调试。
// 
// 信号处理程序调用的入口点将从
// runtime.sigmanic调用，因此我们不能禁止从运行时调用
// 这些（它们看起来总是从运行时调用的）。
// 因此，对于这些，我们只需检查运行时条件是否明显不好。
// 
// panic{Index，Slice}函数在下面的汇编和尾部调用中实现，
// goPanic{Index，Slice}函数。这样我们就可以使用
// 一种空间最小的寄存器调用约定。

// s[x]比较失败，0<=x<y（y==len（s））
func goPanicIndex(x int, y int) {
	panicCheck1(getcallerpc(), "index out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsIndex})
}
func goPanicIndexU(x uint, y int) {
	panicCheck1(getcallerpc(), "index out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex})
}

// s[：x]比较失败，0<=x<=y（y==len（s）或cap（s））
func goPanicSliceAlen(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAlen})
}
func goPanicSliceAlenU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen})
}
func goPanicSliceAcap(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAcap})
}
func goPanicSliceAcapU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap})
}

// s[x:y]比较失败，0<=x<=y 
func goPanicSliceB(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceB})
}
func goPanicSliceBU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB})
}

// s[：x]比较失败，0<=x<=y（y==len s）或cap
func goPanicSlice3Alen(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Alen})
}
func goPanicSlice3AlenU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen})
}
func goPanicSlice3Acap(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Acap})
}
func goPanicSlice3AcapU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap})
}

// s[：x:y]的比较失败，0<=x<=y 
func goPanicSlice3B(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3B})
}
func goPanicSlice3BU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B})
}

// s[x:y:]，0<=x<=y 
func goPanicSlice3C(x int, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3C})
}
func goPanicSlice3CU(x uint, y int) {
	panicCheck1(getcallerpc(), "slice bounds out of range")
	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C})
}

// 转换失败（*[x]T），0<=x<=y，x==cap（s）
func goPanicSliceConvert(x int, y int) {
	panicCheck1(getcallerpc(), "slice length too short to convert to pointer to array")
	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsConvert})
}

// 在汇编中实现，因为它们在寄存器中使用参数。
// 在此处声明，以将其标记为ABIInternal。
func panicIndex(x int, y int)
func panicIndexU(x uint, y int)
func panicSliceAlen(x int, y int)
func panicSliceAlenU(x uint, y int)
func panicSliceAcap(x int, y int)
func panicSliceAcapU(x uint, y int)
func panicSliceB(x int, y int)
func panicSliceBU(x uint, y int)
func panicSlice3Alen(x int, y int)
func panicSlice3AlenU(x uint, y int)
func panicSlice3Acap(x int, y int)
func panicSlice3AcapU(x uint, y int)
func panicSlice3B(x int, y int)
func panicSlice3BU(x uint, y int)
func panicSlice3C(x int, y int)
func panicSlice3CU(x uint, y int)
func panicSliceConvert(x int, y int)

var shiftError = error(errorString("negative shift amount"))

func panicshift() {
	panicCheck1(getcallerpc(), "negative shift amount")
	panic(shiftError)
}

var divideError = error(errorString("integer divide by zero"))

func panicdivide() {
	panicCheck2("integer divide by zero")
	panic(divideError)
}

var overflowError = error(errorString("integer overflow"))

func panicoverflow() {
	panicCheck2("integer overflow")
	panic(overflowError)
}

var floatError = error(errorString("floating point error"))

func panicfloat() {
	panicCheck2("floating point error")
	panic(floatError)
}

var memoryError = error(errorString("invalid memory address or nil pointer dereference"))

func panicmem() {
	panicCheck2("invalid memory address or nil pointer dereference")
	panic(memoryError)
}

func panicmemAddr(addr uintptr) {
	panicCheck2("invalid memory address or nil pointer dereference")
	panic(errorAddressString{msg: "invalid memory address or nil pointer dereference", addr: addr})
}

// 创建一个新的延迟函数fn，其参数大小为siz字节。
// 编译器将DEBER语句转换为对该语句的调用。
// go:nosplit 
func deferproc(siz int32, fn *funcval) { // fn的参数follow fn 
	gp := getg()
	if gp.m.curg != gp {
		// 系统堆栈上的go代码不能延迟
		throw("defer on system stack")
	}

	if goexperiment.RegabiDefer && siz != 0 {
		// TODO:Make deferproc just take func（）。
		throw("defer with non-empty frame")
	}

	// fn的论点处于危险状态。deferproc的堆栈映射
	// 没有描述它们。所以我们不能让垃圾
	// 收集或堆栈复制触发，直到我们将它们复制到安全的地方。下面的memmove就是这样做的。
	// 在复制完成之前，我们只能调用nosplit例程。
	sp := getcallersp()
	argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
	callerpc := getcallerpc()

	d := newdefer(siz)
	if d._panic != nil {
		throw("deferproc: d.panic != nil after newdefer")
	}
	d.link = gp._defer
	gp._defer = d
	d.fn = fn
	d.pc = callerpc
	d.sp = sp
	switch siz {
	case 0:
		// 什么也不做。
	case sys.PtrSize:
		*(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp))
	default:
		memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz))
	}

	// deferproc正常返回0。
	// 一个延迟函数，用于停止一个恐慌
	// 使deferproc返回1。
	// 编译器生成的代码始终
	// 检查返回值并跳转到
	// 如果deferproc返回，则函数结束！=0
	return0()
	// 此处无法输入任何代码-已设置了C返回寄存器
	// 且不能将其删除。
}

// deferprocStack将一个新的延迟函数与堆栈上的延迟记录一起排队。
// 延迟记录必须初始化其siz和fn字段。
// 所有其他字段都可以包含垃圾邮件。
// 延迟记录必须在内存中紧跟着
// 延迟的参数。
// Nosplit，因为在将延迟记录拼接到gp.\u延迟列表之前，不会扫描堆栈上的参数。
// go:nosplit 
func deferprocStack(d *_defer) {
	gp := getg()
	if gp.m.curg != gp {
		// 系统堆栈上的go代码无法延迟
		throw("defer on system stack")
	}
	if goexperiment.RegabiDefer && d.siz != 0 {
		throw("defer with non-empty frame")
	}
	// 已设置大小和fn。
	// 其他字段在deferprocStack的条目中是垃圾字段，
	// 在此处初始化。
	d.started = false
	d.heap = false
	d.openDefer = false
	d.sp = getcallersp()
	d.pc = getcallerpc()
	d.framepc = 0
	d.varp = 0
	// 下面的行实现：
	// d.panic=nil 
	// d.fd=nil 
	// d.link=gp.\u defer 
	// gp。前三个是对堆栈的写入，因此它们不需要写屏障，而且
	// 是对未初始化内存的写入，因此它们不能使用写屏障。
	// 第四次写入不需要写屏障，因为我们
	// 显式标记所有延迟结构，所以我们不需要
	// 使用写屏障跟踪指向它们的指针。
	*(*uintptr)(unsafe.Pointer(&d._panic)) = 0
	*(*uintptr)(unsafe.Pointer(&d.fd)) = 0
	*(*uintptr)(unsafe.Pointer(&d.link)) = uintptr(unsafe.Pointer(gp._defer))
	*(*uintptr)(unsafe.Pointer(&gp._defer)) = uintptr(unsafe.Pointer(d))

	return0()
	// 此处无法输入任何代码-已设置了C返回寄存器
	// 且不能将其删除。
}

// 小malloc大小类>=16是16的倍数：16、32、48、64、80、96、112、128、144、。。。
// 每个P都有一个池，用于存放具有较小参数大小的延迟。
// 通过四舍五入到16，将延迟分配分配分配给池，以匹配malloc大小的类。

const (
	deferHeaderSize = unsafe.Sizeof(_defer{})
	minDeferAlloc   = (deferHeaderSize + 15) &^ 15
	minDeferArgs    = minDeferAlloc - deferHeaderSize
)

// arg size sz的延迟大小类
// go:nosplit 
func deferclass(siz uintptr) uintptr {
	if siz <= minDeferArgs {
		return 0
	}
	return (siz - minDeferArgs + 15) / 16
}

// arg size sz的延迟内存块的总大小
func totaldefersize(siz uintptr) uintptr {
	if siz <= minDeferArgs {
		return minDeferAlloc
	}
	return deferHeaderSize + siz
}

// 确保映射到相同延迟大小类
// 的延迟参数大小也映射到相同的malloc size类。
func testdefersizes() {
	var m [len(p{}.deferpool)]int32

	for i := range m {
		m[i] = -1
	}
	for i := uintptr(0); ; i++ {
		defersc := deferclass(i)
		if defersc >= uintptr(len(m)) {
			break
		}
		siz := roundupsize(totaldefersize(i))
		if m[defersc] < 0 {
			m[defersc] = int32(siz)
			continue
		}
		if m[defersc] != int32(siz) {
			print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n")
			throw("bad defer size class")
		}
	}
}

// 与延迟调用关联的参数存储在内存中的_defer头之后。
// go:nosplit 
func deferArgs(d *_defer) unsafe.Pointer {
	if d.siz == 0 {
		// 避免指针超过延迟分配。
		return nil
	}
	return add(unsafe.Pointer(d), unsafe.Sizeof(*d))
}

// deferFunc返回d的延迟函数。这是暂时的，而我们
// 支持GOEXPERIMENT=regabidefer的两种模式。一旦我们承诺进行实验，我们就应该改变d.fn的类型。
// go:nosplit 
func deferFunc(d *_defer) func() {
	if !goexperiment.RegabiDefer {
		throw("requires GOEXPERIMENT=regabidefer")
	}
	var fn func()
	*(**funcval)(unsafe.Pointer(&fn)) = d.fn
	return fn
}

var deferType *_type // 类型的_defer结构

func init() {
	var x interface{}
	x = (*_defer)(nil)
	deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem
}

// 分配一个延迟，通常使用per-P池。
// 必须使用freedefer释放每个延迟。延迟尚未添加到任何延迟链中。
// 
// 这不能增加堆栈，因为调用它时可能有一个帧没有
// 堆栈映射信息。
// 
// go:nosplit 
func newdefer(siz int32) *_defer {
	var d *_defer
	sc := deferclass(uintptr(siz))
	gp := getg()
	if sc < uintptr(len(p{}.deferpool)) {
		pp := gp.m.p.ptr()
		if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
			// 在系统堆栈上走慢路径，这样
			// 我们就不会增加newdefer的堆栈。
			systemstack(func() {
				lock(&sched.deferlock)
				for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
					d := sched.deferpool[sc]
					sched.deferpool[sc] = d.link
					d.link = nil
					pp.deferpool[sc] = append(pp.deferpool[sc], d)
				}
				unlock(&sched.deferlock)
			})
		}
		if n := len(pp.deferpool[sc]); n > 0 {
			d = pp.deferpool[sc][n-1]
			pp.deferpool[sc][n-1] = nil
			pp.deferpool[sc] = pp.deferpool[sc][:n-1]
		}
	}
	if d == nil {
		// 分配新的延迟+参数。
		systemstack(func() {
			total := roundupsize(totaldefersize(uintptr(siz)))
			d = (*_defer)(mallocgc(total, deferType, true))
		})
	}
	d.siz = siz
	d.heap = true
	return d
}

// 释放给定延迟。
// 此调用后无法使用延迟。
// 
// 这不能使堆栈增长，因为调用它时可能有一个帧没有
// 堆栈映射。
// 
// go:nosplit 
func freedefer(d *_defer) {
	if d._panic != nil {
		freedeferpanic()
	}
	if d.fn != nil {
		freedeferfn()
	}
	if !d.heap {
		return
	}
	sc := deferclass(uintptr(d.siz))
	if sc >= uintptr(len(p{}.deferpool)) {
		return
	}
	pp := getg().m.p.ptr()
	if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
		// 将本地缓存的一半传输到中央缓存。
		// 
		// 在系统堆栈上走这条慢路径，这样我们就不会增加freedefer的堆栈。
		systemstack(func() {
			var first, last *_defer
			for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
				n := len(pp.deferpool[sc])
				d := pp.deferpool[sc][n-1]
				pp.deferpool[sc][n-1] = nil
				pp.deferpool[sc] = pp.deferpool[sc][:n-1]
				if first == nil {
					first = d
				} else {
					last.link = d
				}
				last = d
			}
			lock(&sched.deferlock)
			last.link = sched.deferpool[sc]
			sched.deferpool[sc] = first
			unlock(&sched.deferlock)
		})
	}

	// 这些行过去只是`*d=_defer{}`但
	// 开始通过typedmemmove导致nosplit堆栈溢出。
	d.siz = 0
	d.started = false
	d.openDefer = false
	d.sp = 0
	d.pc = 0
	d.framepc = 0
	d.varp = 0
	d.fd = nil
	// d.\u恐慌和d.fn必须已经为零。
	// 如果不是，我们会在上面称为freedeferpanic或freedeferfn，
	// 这两个都会抛出。
	d.link = nil

	pp.deferpool[sc] = append(pp.deferpool[sc], d)
}

// 分离函数以便可以拆分堆栈。
// 否则Windows将耗尽堆栈空间。
func freedeferpanic() {
	// /\u必须在d与gp解除链接之前清除恐慌。
	throw("freedefer with d._panic != nil")
}

func freedeferfn() {
	// 在d与gp解除链接之前，必须清除fn。
	throw("freedefer with d.fn != nil")
}

// 如果有延迟函数，请运行延迟函数。
// 编译器在调用defer的任何
// 函数的末尾插入对此函数的调用。
// 如果有一个延迟函数，这将调用runtime·jmpdefer，
// 该函数将跳转到延迟函数，从而使
// 在调用deferreturn之前的点
// 处被deferreturn的调用方调用。其效果是一次又一次地调用deferreturn 
// 直到不再有延迟函数为止。
// 
// 声明为nosplit，因为一旦启动
// 修改调用方的帧以重用该帧来调用延迟的
// 函数，该函数不应被抢占。
// 
// go:nosplit 
func deferreturn() {
	gp := getg()
	d := gp._defer
	if d == nil {
		return
	}
	sp := getcallersp()
	if d.sp != sp {
		return
	}
	if d.openDefer {
		done := runOpenDeferFrame(gp, d)
		if !done {
			throw("unfinished open-coded defers in deferreturn")
		}
		gp._defer = d.link
		freedefer(d)
		return
	}

	// 移动参数。
	// 
	// 在这一点之后调用的所有内容都必须是递归的
	// nosplit，因为在jmpdefer将PC翻转到
	// 。
	// fn之前，垃圾收集器不会知道参数的形式
	argp := getcallersp() + sys.MinFrameSize
	switch d.siz {
	case 0:
		// 什么也不做。
	case sys.PtrSize:
		*(*uintptr)(unsafe.Pointer(argp)) = *(*uintptr)(deferArgs(d))
	default:
		memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz))
	}
	fn := d.fn
	d.fn = nil
	gp._defer = d.link
	freedefer(d)
	// 如果延迟函数指针为nil，则强制seg错误在此处而不是在jmpdefer中发生。gentraceback（）在LR体系结构上使用回调调用
	// 并且jmpdefer位于
	// 堆栈上时抛出错误，因为在这种情况下堆栈跟踪可能不正确-请参阅
	// 问题#8153）。
	_ = fn.fn
	jmpdefer(fn, argp)
}

// Goexit终止调用它的goroutine。没有其他goroutine受到影响。
// Goexit在终止goroutine之前运行所有延迟调用。因为Goexit 
// 不是恐慌，所以这些延迟函数中的任何recover调用都将返回nil。
// 
// 从主goroutine调用Goexit终止该goroutine 
// 而不返回func main。由于func main尚未返回，
// 程序将继续执行其他goroutine。
// 如果所有其他goroutine都退出，程序将崩溃。
func Goexit() {
	// 运行当前goroutine的所有延迟函数。
	// 此代码类似于gopanic，有关详细注释，请参阅实现
	// 。
	gp := getg()

	// 为Goexit创建一个panic对象，这样我们就可以识别何时它可能被recover（）绕过。
	var p _panic
	p.goexit = true
	p.link = gp._panic
	gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))

	addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp()))
	for {
		d := gp._defer
		if d == nil {
			break
		}
		if d.started {
			if d._panic != nil {
				d._panic.aborted = true
				d._panic = nil
			}
			if !d.openDefer {
				d.fn = nil
				gp._defer = d.link
				freedefer(d)
				continue
			}
		}
		d.started = true
		d._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
		if d.openDefer {
			done := runOpenDeferFrame(gp, d)
			if !done {
				// 我们应该始终运行帧中的所有延迟，
				// 因为没有与此
				// 延迟相关的可以恢复的死机。
				throw("unfinished open-coded defers in Goexit")
			}
			if p.aborted {
				// 由于我们当前的延迟导致了一场恐慌，可能
				// 已经被释放，只需重新启动扫描
				// 以再次查看此帧的开放编码延迟。
				addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp()))
			} else {
				addOneOpenDeferFrame(gp, 0, nil)
			}
		} else {
			if goexperiment.RegabiDefer {
				// 将pc/sp保存在deferCallSave（）中，以便在必要时可以“恢复”到此
				// 循环。
				deferCallSave(&p, deferFunc(d))
			} else {
				// 将pc/sp保存在reflectcallSave（）中，以便我们可以在必要时“恢复”到此
				// 循环。
				reflectcallSave(&p, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz))
			}
		}
		if p.aborted {
			// 我们在开始的延迟d中遇到了一个递归恐慌，然后
			// 在一个延迟中进行了恢复，该延迟在
			// 延迟链中比d更靠后。对于未完成的Goexit，
			// 我们强制恢复返回到此循环。d如果完成，
			// 将被释放，因此只需立即继续
			// 到链上的下一个延迟。
			p.aborted = false
			continue
		}
		if gp._defer != d {
			throw("bad defer entry in Goexit")
		}
		d._panic = nil
		d.fn = nil
		gp._defer = d.link
		freedefer(d)
		// 注意：我们在这里忽略恢复，因为Goexit并不是一种恐慌
	}
	goexit1()
}

// 在冻结世界之前调用所有错误和字符串方法。
// 因恐慌而崩溃时使用。
func preprintpanics(p *_panic) {
	defer func() {
		if recover() != nil {
			throw("panic while printing panic value")
		}
	}()
	for p != nil {
		switch v := p.arg.(type) {
		case error:
			p.arg = v.Error()
		case stringer:
			p.arg = v.String()
		}
		p = p.link
	}
}

// 打印所有当前活动的恐慌。碰撞时使用。
// 只能在预印本之后调用。
func printpanics(p *_panic) {
	if p.link != nil {
		printpanics(p.link)
		if !p.link.goexit {
			print("\t")
		}
	}
	if p.goexit {
		return
	}
	print("panic: ")
	printany(p.arg)
	if p.recovered {
		print(" [recovered]")
	}
	print("\n")
}

// addOneOpenDeferFrame使用
// 打开编码的延迟扫描堆栈中的第一个帧（如果有），如果找到，则向该帧的延迟链
// 添加一条记录。如果sp为非nil，则从帧
// 由sp指定。如果sp为nil，则使用当前延迟记录
// （刚刚完成）中的sp。因此，它从刚刚完成的延迟的
// 帧继续堆栈扫描。它跳过任何已经有
// 开放编码的延迟记录的帧，该延迟记录是从以前的
// （未恢复）恐慌中创建的。
// 
// 注意：延迟链的所有条目（包括这个新的开放编码条目）都有
// 如果堆栈在运行延迟函数时移动，它们的指针（包括sp）会得到适当调整。另外，可以安全地传入sp arg（即
// /调用getcallersp（）的直接结果），因为在堆栈复制期间，所有指针变量
// （包括参数）都会根据需要进行调整。
func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) {
	var prevDefer *_defer
	if sp == nil {
		prevDefer = gp._defer
		pc = prevDefer.framepc
		sp = unsafe.Pointer(prevDefer.sp)
	}
	systemstack(func() {
		gentraceback(pc, uintptr(sp), 0, gp, 0, nil, 0x7fffffff,
			func(frame *stkframe, unused unsafe.Pointer) bool {
				if prevDefer != nil && prevDefer.sp == frame.sp {
					// 跳过上次延迟的帧
					// 我们刚刚完成（用于设置
					// 我们重新启动堆栈扫描的位置）
					return true
				}
				f := frame.fn
				fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo)
				if fd == nil {
					return true
				}
				// 在
				// 链中插入打开的延迟记录，按sp.
				d := gp._defer
				var prev *_defer
				for d != nil {
					dsp := d.sp
					if frame.sp < dsp {
						break
					}
					if frame.sp == dsp {
						if !d.openDefer {
							throw("duplicated defer entry")
						}
						return true
					}
					prev = d
					d = d.link
				}
				if frame.fn.deferreturn == 0 {
					throw("missing deferreturn")
				}

				maxargsize, _ := readvarintUnsafe(fd)
				d1 := newdefer(int32(maxargsize))
				d1.openDefer = true
				d1._panic = nil
				// 排序，这些是在我们执行
				// 后要设置的pc/sp，该帧执行了
				// 恢复。我们返回一个特殊的
				// deferreturn，它运行任何剩余的
				// defers，然后从
				// 函数返回。
				d1.pc = frame.fn.entry + uintptr(frame.fn.deferreturn)
				d1.varp = frame.varp
				d1.fd = fd
				// 保存与当前帧关联的SP/PC，
				// 以便我们可以在以后需要时继续堆栈跟踪。
				d1.framepc = frame.pc
				d1.sp = frame.sp
				d1.link = d
				if prev == nil {
					gp._defer = d1
				} else {
					prev.link = d1
				}
				// 添加一条打开的延迟记录后停止堆栈扫描
				return false
			},
			nil, 0)
	})
}

// ReadVarintSafe从fd开始以varint格式读取uint32，并返回
// uint32和指向varint后面字节的指针。
// 
// 有一个类似的函数runtime.readvarint，它需要一个字节片，而不是一个不安全的指针。这些函数是重复的，因为
// 如果将两个函数组合在一起，则函数的两个用例会变慢。
func readvarintUnsafe(fd unsafe.Pointer) (uint32, unsafe.Pointer) {
	var r uint32
	var shift int
	for {
		b := *(*uint8)((unsafe.Pointer(fd)))
		fd = add(fd, unsafe.Sizeof(b))
		if b < 128 {
			return r + uint32(b)<<shift, fd
		}
		r += ((uint32(b) &^ 128) << shift)
		shift += 7
		if shift > 28 {
			panic("Bad varint")
		}
	}
}

// runOpenDeferFrame在
// d指定的帧中运行活动的开放编码延迟。它通常处理帧中所有活动的延迟，但如果延迟成功恢复，则会立即停止
// 操作。如果没有
// 要在帧中运行的剩余延迟，则返回true。
func runOpenDeferFrame(gp *g, d *_defer) bool {
	done := true
	fd := d.fd

	// 跳过maxargsize 
	_, fd = readvarintUnsafe(fd)
	deferBitsOffset, fd := readvarintUnsafe(fd)
	nDefers, fd := readvarintUnsafe(fd)
	deferBits := *(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset)))

	for i := int(nDefers) - 1; i >= 0; i-- {
		// 读取此延迟的funcdata信息
		var argWidth, closureOffset, nArgs uint32
		argWidth, fd = readvarintUnsafe(fd)
		closureOffset, fd = readvarintUnsafe(fd)
		nArgs, fd = readvarintUnsafe(fd)
		if goexperiment.RegabiDefer && argWidth != 0 {
			throw("defer with non-empty frame")
		}
		if deferBits&(1<<i) == 0 {
			for j := uint32(0); j < nArgs; j++ {
				_, fd = readvarintUnsafe(fd)
				_, fd = readvarintUnsafe(fd)
				_, fd = readvarintUnsafe(fd)
			}
			continue
		}
		closure := *(**funcval)(unsafe.Pointer(d.varp - uintptr(closureOffset)))
		d.fn = closure
		deferArgs := deferArgs(d)
		// 如果有接口接收器或方法接收器，则
		// 作为第一个参数描述/包含。
		for j := uint32(0); j < nArgs; j++ {
			var argOffset, argLen, argCallOffset uint32
			argOffset, fd = readvarintUnsafe(fd)
			argLen, fd = readvarintUnsafe(fd)
			argCallOffset, fd = readvarintUnsafe(fd)
			memmove(unsafe.Pointer(uintptr(deferArgs)+uintptr(argCallOffset)),
				unsafe.Pointer(d.varp-uintptr(argOffset)),
				uintptr(argLen))
		}
		deferBits = deferBits &^ (1 << i)
		*(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits
		p := d._panic
		if goexperiment.RegabiDefer {
			deferCallSave(p, deferFunc(d))
		} else {
			reflectcallSave(p, unsafe.Pointer(closure), deferArgs, argWidth)
		}
		if p != nil && p.aborted {
			break
		}
		d.fn = nil
		// 这些参数只是一个副本，因此可以在将呼叫者的pc和sp保存到
		memclrNoHeapPointers(deferArgs, uintptr(argWidth))
		if d._panic != nil && d._panic.recovered {
			done = deferBits == 0
			break
		}
	}

	return done
}

// 紧急记录中后立即清除。这允许运行时返回Goexit defer processing 
// 循环，在异常情况下，Goexit可能被成功的
// 恢复绕过。
// 
// 编译器将其标记为包装器，因此它不会出现在
// 回溯中。
func reflectcallSave(p *_panic, fn, arg unsafe.Pointer, argsize uint32) {
	if goexperiment.RegabiDefer {
		throw("not allowed with GOEXPERIMENT=regabidefer")
	}
	if p != nil {
		p.argp = unsafe.Pointer(getargp())
		p.pc = getcallerpc()
		p.sp = unsafe.Pointer(getcallersp())
	}
	// 传递一个伪RegArgs，因为只有在
	// 我们没有使用寄存器ABI时，我们才会使用此路径。
	var regs abi.RegArgs
	reflectcall(nil, fn, arg, argsize, argsize, argsize, &regs)
	if p != nil {
		p.pc = 0
		p.sp = unsafe.Pointer(nil)
	}
}

// 在
// 紧急记录中保存调用方的pc和sp后，延迟CallSave调用fn（）。这允许运行时返回Goexit defer 
// 处理循环，在Goexit可能被成功恢复绕过的异常情况下。
// 
// 编译器将其标记为包装器，因此它不会出现在
// 回溯中。
func deferCallSave(p *_panic, fn func()) {
	if !goexperiment.RegabiDefer {
		throw("only allowed with GOEXPERIMENT=regabidefer")
	}
	if p != nil {
		p.argp = unsafe.Pointer(getargp())
		p.pc = getcallerpc()
		p.sp = unsafe.Pointer(getcallersp())
	}
	fn()
	if p != nil {
		p.pc = 0
		p.sp = unsafe.Pointer(nil)
	}
}

// 预声明函数的实现。
func gopanic(e interface{}) {
	gp := getg()
	if gp.m.curg != gp {
		print("panic: ")
		printany(e)
		print("\n")
		throw("panic on system stack")
	}

	if gp.m.mallocing != 0 {
		print("panic: ")
		printany(e)
		print("\n")
		throw("panic during malloc")
	}
	if gp.m.preemptoff != "" {
		print("panic: ")
		printany(e)
		print("\n")
		print("preempt off reason: ")
		print(gp.m.preemptoff)
		print("\n")
		throw("panic during preemptoff")
	}
	if gp.m.locks != 0 {
		print("panic: ")
		printany(e)
		print("\n")
		throw("panic holding locks")
	}

	var p _panic
	p.arg = e
	p.link = gp._panic
	gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))

	atomic.Xadd(&runningPanicDefers, 1)

	// 通过在此处计算getCallerRPC/getcallersp，我们可以避免扫描
	// gopanic帧（堆栈扫描很慢…）
	addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp()))

	for {
		d := gp._defer
		if d == nil {
			break
		}

		// 如果延迟是由早期的panic或Goexit启动的（由于我们回到这里，这触发了新的恐慌），
		// 将延迟从列表中删除。早些时候的恐慌不会继续，但我们将在下面确保
		// 早些时候的Goexit会继续运行。
		if d.started {
			if d._panic != nil {
				d._panic.aborted = true
			}
			d._panic = nil
			if !d.openDefer {
				// 对于开放编码的延迟，我们需要再次处理
				// 延迟，以防帧中有任何其他延迟
				// 调用（不包括导致恐慌的延迟
				// 调用）。
				d.fn = nil
				gp._defer = d.link
				freedefer(d)
				continue
			}
		}

		// 将延迟标记为已启动，但保留在列表中，以便在堆栈增长
		// 可以找到并更新延迟的参数帧。
		// 或在执行d.fn之前发生垃圾收集时，回溯
		d.started = true

		// 记录运行延迟的死机。
		// 如果在延迟呼叫期间出现新的恐慌，该恐慌
		// 将在列表中找到d并将标记为d。_恐慌（此恐慌）中止。
		d._panic = (*_panic)(noescape(unsafe.Pointer(&p)))

		done := true
		if d.openDefer {
			done = runOpenDeferFrame(gp, d)
			if done && !d._panic.recovered {
				addOneOpenDeferFrame(gp, 0, nil)
			}
		} else {
			p.argp = unsafe.Pointer(getargp())

			if goexperiment.RegabiDefer {
				fn := deferFunc(d)
				fn()
			} else {
				// 传递一个伪RegArgs，因为只有在
				// 我们没有使用寄存器ABI时，我们才会使用此路径。
				var regs abi.RegArgs
				reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz), uint32(d.siz), &regs)
			}
		}
		p.argp = nil

		// 延迟函数没有死机。删除d。
		if gp._defer != d {
			throw("bad defer entry in panic")
		}
		d._panic = nil

		// 触发收缩以测试堆栈副本。请参阅stack_test.go:TestStackPanic 
		// GC（）

		pc := d.pc
		sp := unsafe.Pointer(d.sp) // 必须是指针，以便在堆栈复制期间对其进行调整
		if done {
			d.fn = nil
			gp._defer = d.link
			freedefer(d)
		}
		if p.recovered {
			gp._panic = p.link
			if gp._panic != nil && gp._panic.goexit && gp._panic.aborted {
				// 正常恢复将绕过/中止Goexit。相反，我们返回到Goexit的处理循环。
				gp.sigcode0 = uintptr(gp._panic.sp)
				gp.sigcode1 = uintptr(gp._panic.pc)
				mcall(recovery)
				throw("bypassed recovery failed") // mcall不应返回
			}
			atomic.Xadd(&runningPanicDefers, -1)

			// 删除任何剩余的未启动、开放编码的
			// 恢复后延迟条目，因为
			// 相应的延迟将正常执行
			// /（内联）。一旦
			// 我们运行相应的延迟内联并退出
			// 相关堆栈帧，任何此类条目都将过时。
			d := gp._defer
			var prev *_defer
			if !done {
				// 如果未完成，请跳过当前帧。它是
				prev = d
				d = d.link
			}
			for d != nil {
				if d.started {
					// 进一步延迟条目
					break
				}
				if d.openDefer {
					if prev == nil {
						gp._defer = d.link
					} else {
						prev.link = d.link
					}
					newd := d.link
					freedefer(d)
					d = newd
				} else {
					prev = d
					d = d.link
				}
			}

			gp._panic = p.link
			// 已标记中止的恐慌，但仍保留在g.panic列表中。
			// 将其从列表中删除。
			for gp._panic != nil && gp._panic.aborted {
				gp._panic = gp._panic.link
			}
			if gp._panic == nil { // 必须使用信号
				gp.sig = 0
			}
			// 将有关恢复帧的信息传递给恢复。
			gp.sigcode0 = uintptr(sp)
			gp.sigcode1 = pc
			mcall(recovery)
			throw("recovery failed") // McCall不应返回
		}
	}

	// 延迟呼叫用完-旧式恐慌现在
	// 因为冻结
	// 世界后调用任意用户代码是不安全的，我们调用preprintpanics来调用所有必要的错误
	// 和String方法来在startpanic之前准备panic字符串。
	preprintpanics(gp._panic)

	fatalpanic(gp._panic) // 不应返回
	*(*int)(nil) = 0      // 未到达
}

// getargp返回调用方
// 写入传出函数调用参数的位置。
// go:nosplit 
// go:noinline 
func getargp() uintptr {
	return getcallersp() + sys.MinFrameSize
}

// 预声明函数recover的实现。
// 无法拆分堆栈，因为它需要可靠地找到调用方的堆栈段。
// 
// TODO（rsc）：一旦我们始终承诺CopyStackAlways，
// /这不需要被拆分。
// go:nosplit 
func gorecover(argp uintptr) interface{} {
	// 必须位于函数中，该函数在紧急情况下作为延迟调用的一部分运行。
	// 必须从调用
	// （DEBER语句中使用的函数）的最顶端函数调用。
	// p.argp是最上面的延迟函数调用的参数指针。
	// 与调用方报告的argp进行比较。
	// 如果匹配，则呼叫方是可以恢复的。
	gp := getg()
	p := gp._panic
	if p != nil && !p.goexit && !p.recovered && argp == uintptr(p.argp) {
		p.recovered = true
		return p.arg
	}
	return nil
}

// go:linkname sync\u throw sync.throw 
func sync_throw(s string) {
	throw(s)
}

// go:nosplit 
func throw(s string) {
	// throw所做的一切都应该是递归的nosplit，这样即使在堆栈增长不安全的情况下也可以调用它。
	systemstack(func() {
		print("fatal error: ", s, "\n")
	})
	gp := getg()
	if gp.m.throwing == 0 {
		gp.m.throwing = 1
	}
	fatalthrow()
	*(*int)(nil) = 0 // 未达到
}

// 在为死机运行延迟函数时，RunningPanicDeferres为非零。
// runningPanicDefers以原子方式递增和递减。
// 用于在退出时尽力获取紧急堆栈跟踪。
var runningPanicDefers uint32

// 当程序因未恢复的恐慌而崩溃时，恐慌不为零。
// 恐慌在原子上递增和递减。
var panicking uint32

// 在打印死机信息和堆栈跟踪时，会保留paniclk，
// 这样两个并发的死机不会重叠其输出。
var paniclk mutex

// 在延迟函数调用后解除堆栈恢复
// 在死机后。然后安排继续运行，就像
// 延迟函数的调用方正常返回一样。
func recovery(gp *g) {
	// 有关在G结构中传递的延迟的信息。
	sp := gp.sigcode0
	pc := gp.sigcode1

	// d的参数需要在堆栈中。
	if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) {
		print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
		throw("bad recovery")
	}

	// 再次执行此d返回的延迟过程，
	// 这次返回1。调用函数将
	// 跳转到标准返回尾声。
	gp.sched.sp = sp
	gp.sched.pc = pc
	gp.sched.lr = 0
	gp.sched.ret = 1
	gogo(&gp.sched)
}

// fatalthrow实现不可恢复的运行时抛出。它冻结
// 系统，打印从调用方开始的堆栈跟踪，并终止
// 过程。
// 
// go:nosplit 
func fatalthrow() {
	pc := getcallerpc()
	sp := getcallersp()
	gp := getg()
	// 切换到系统堆栈以避免任何堆栈增长，如果运行时处于不良状态，这可能会使情况变得更糟。
	systemstack(func() {
		startpanic_m()

		if dopanic_m(gp, pc, sp) {
			// crash使用了相当数量的nosplit堆栈，而且我们的堆栈抛出量已经很低，因此系统堆栈上会发生崩溃（与
			// fatalpanic不同）。
			crash()
		}

		exit(2)
	})

	*(*int)(nil) = 0 // 未到达
}

// fatalpanic执行无法恢复的紧急状态。除了
// 如果msgs！=无，fatalpanic也会打印紧急消息，并在main被阻止退出后减少
// 运行紧急延迟。
// 
// go:nosplit 
func fatalpanic(msgs *_panic) {
	pc := getcallerpc()
	sp := getcallersp()
	gp := getg()
	var docrash bool
	// 切换到系统堆栈以避免任何堆栈增长，如果运行时处于错误状态，这可能会使情况变得更糟。
	systemstack(func() {
		if startpanic_m() && msgs != nil {
			// 有恐慌信息，startpanic_m 
			// 表示可以尝试打印这些信息。

			// 启动NIC_m set恐慌，这将阻止main退出，因此现在确定
			// 减量运行恐慌延迟。
			atomic.Xadd(&runningPanicDefers, -1)

			printpanics(msgs)
		}

		docrash = dopanic_m(gp, pc, sp)
	})

	if docrash {
		// 通过在上述systemstack调用之外崩溃，调试器
		// 在生成回溯跟踪时不会混淆。
		// 将函数崩溃标记为nosplit以避免堆栈增长。
		crash()
	}

	systemstack(func() {
		exit(2)
	})

	*(*int)(nil) = 0 // 未联系到
}

// 启动NIC\u m为无法恢复的恐慌做好准备。
// 
// 如果应该打印紧急消息，则返回true；如果
// 则返回false。运行时状态不好，应该只打印堆栈。
// 
// 即使写屏障
// 在死后显式忽略写入>0，也不能有写屏障。写屏障仍然
// 假设g.m.p！=nil，并且在某些上下文中，此函数可能没有P 
// （例如，在信号处理程序中，信号
// 发送到没有P的M时出现死机）。
// 
// go:nowritebarrierrec 
func startpanic_m() bool {
	_g_ := getg()
	if mheap_.cachealloc.size == 0 { // 非常早的
		print("runtime: panic before malloc heap initialized\n")
	}
	// 在无法恢复的恐慌中不允许马洛克。恐慌可能发生在信号处理程序中，也可能发生在抛出中，或者发生在
	// malloc本身内部。我们想知道是否发生过分配
	// 的情况（即使我们没有遇到这种情况）。
	_g_.m.mallocing++

	// 如果我们因为锁计数错误而死亡，请将其设置为
	// 锁计数正确，这样我们就不会在下面递归地恐慌。
	if _g_.m.locks < 0 {
		_g_.m.locks = 1
	}

	switch _g_.m.dying {
	case 0:
		// 设置DINGE>0的副作用是禁用此G的writebuf。
		_g_.m.dying = 1
		atomic.Xadd(&panicking, 1)
		lock(&paniclk)
		if debug.schedtrace > 0 || debug.scheddetail > 0 {
			schedtrace(true)
		}
		freezetheworld()
		return true
	case 1:
		// 在恐慌中失败了。
		// 只需打印堆栈跟踪并退出即可。
		_g_.m.dying = 2
		print("panic during panic\n")
		return false
	case 2:
		// 这在运行时是一个真正的错误，我们甚至无法成功打印堆栈跟踪。
		_g_.m.dying = 3
		print("stack trace unavailable\n")
		exit(4)
		fallthrough
	default:
		// 甚至无法打印！出去吧。
		exit(5)
		return false // 需要归还一些东西。
	}
}

var didothers bool
var deadlock mutex

func dopanic_m(gp *g, pc, sp uintptr) bool {
	if gp.sig != 0 {
		signame := signame(gp.sig)
		if signame != "" {
			print("[signal ", signame)
		} else {
			print("[signal ", hex(gp.sig))
		}
		print(" code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
	}

	level, all, docrash := gotraceback()
	_g_ := getg()
	if level > 0 {
		if gp != gp.m.curg {
			all = true
		}
		if gp != gp.m.g0 {
			print("\n")
			goroutineheader(gp)
			traceback(pc, sp, 0, gp)
		} else if level >= 2 || _g_.m.throwing > 0 {
			print("\nruntime stack:\n")
			traceback(pc, sp, 0, gp)
		}
		if !didothers && all {
			didothers = true
			tracebackothers(gp)
		}
	}
	unlock(&paniclk)

	if atomic.Xadd(&panicking, -1) != 0 {
		// 其他一些m也在恐慌。
		// 让它打印需要打印的内容。
		// 永远等待，不要占用cpu。
		// 完成后将退出。
		lock(&deadlock)
		lock(&deadlock)
	}

	printDebugLog()

	return docrash
}

// 如果信号应该抛出而不是
// 惊慌，则canpanic返回false。
// 
// go:nosplit 
func canpanic(gp *g) bool {
	// 注意g是m->gsignal，不同于gp。
	// 请注意，g->m可以在抢占时更改，因此如果此函数调用函数，m可能会过时。
	_g_ := getg()
	_m_ := _g_.m

	// gp恐慌而不是破坏程序可以吗？
	// 是的，只要它运行的是Go代码，而不是运行时代码，
	// 并且没有陷入系统调用。
	if gp == nil || gp != _m_.curg {
		return false
	}
	if _m_.locks != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
		return false
	}
	status := readgstatus(gp)
	if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
		return false
	}
	if GOOS == "windows" && _m_.libcallsp != 0 {
		return false
	}
	return true
}

// shouldPushSigmanic报告pc是否应用作Sigmanic的
// 返回pc（为调用推送帧）。否则，它应该是
// 单独使用，以便LR被用作SIGMANIC的返回PC，实际上
// 用SIGMANIC替换最上面的帧。这是
// /preparePanic使用的。
func shouldPushSigpanic(gp *g, pc, lr uintptr) bool {
	if pc == 0 {
		// 可能是对nil func的调用。旧的LR在堆栈跟踪中更有用。不按帧
		// 将使跟踪看起来像是对SIGMANIC 
		// 的调用。（否则，跟踪将以sigmanic 
		// 结束，我们将无法看到谁出了故障。）
		return false
	}
	// 如果我们不将PC识别为代码，但我们确实将链接寄存器识别为代码，那么这将假定该恐慌是由非代码调用引起的。在这种情况下，我们想要
	// 忽略此调用以使展开显示上下文。
	// 
	// 如果我们运行C代码，我们不会将pc识别为
	// Go函数，所以假设它是好的。否则，回溯
	// 可能会尝试读取一个看起来像Go代码
	// 指针的陈旧LR，然后漫步到树林中。
	if gp.m.incgo || findfunc(pc).valid() {
		// 这不是一个错误的呼叫，所以使用PC作为Sigmanic的返回PC。
		return true
	}
	if findfunc(lr).valid() {
		// 这是一个错误的呼叫，但LR是好的，所以使用
		// LR作为Sigmanic的返回PC。
		return false
	}
	// PC或LR都不好。希望推动
	// 的框架将起作用。
	return true
}

// isAbortPC报告pc是否是
// runtime.abort发出信号的程序计数器。
// 
// 它是不完整的，因为它是isgoexception 
// 实现的一部分。
// 
// go:nosplit 
func isAbortPC(pc uintptr) bool {
	f := findfunc(pc)
	if !f.valid() {
		return false
	}
	return f.funcID == funcID_abort
}
